package georah.map.layers
{

	import flash.display.Bitmap;
	import flash.display.BitmapData;
	import flash.display.Loader;
	import flash.display.Shape;
	import flash.events.Event;
	import flash.events.IOErrorEvent;
	import flash.events.SecurityErrorEvent;
	import flash.geom.Matrix;
	import flash.system.LoaderContext;
	
	import georah.carto.geometries.OGCPoint;
	import georah.map.MapEvent;
	
	import mx.core.BitmapAsset;
	import mx.core.UIComponent;

	/**
	 *
	 * @author yuanm
	 */
	public class ImageLayer extends MapLayer
	{
		protected var layerContainer:UIComponent=new UIComponent();

		protected var layerMask:Shape=new Shape();

		protected var loaderContext:LoaderContext=new LoaderContext();

		[Embed(source="assets/georah/map/layers/Loading.png")]
		private var DefaultLoadingAsset:Class;

		[Embed(source="assets/georah/map/layers/Unavailable.png")]
		private var DefaultUnavailableAsset:Class;

		private var _usePreview:Boolean=false;

		public final function get usePreview():Boolean
		{
			return _usePreview;
		}

		public final function set usePreview(value:Boolean):void
		{
			_usePreview=value;
			loaderContext.checkPolicyFile=_usePreview;
		}

		protected final function cleanLoader(loader:Loader):void
		{
			try
			{
				(loader.contentLoaderInfo.content as Bitmap).bitmapData.dispose();
			}
			catch (e:*)
			{
				//IGNORE
			}
			loader.unload();
			loader.close();
		}

		override protected function createChildren():void
		{
			super.createChildren();

			addChild(layerMask);
			addChild(layerContainer);
		}

		protected final function createLoader():Loader
		{
			var loader:Loader=new Loader();
			loader.contentLoaderInfo.addEventListener(Event.COMPLETE, loader_completeHandler);
			loader.contentLoaderInfo.addEventListener(IOErrorEvent.IO_ERROR, loader_ioErrorHandler);
			loader.contentLoaderInfo.addEventListener(SecurityErrorEvent.SECURITY_ERROR, loader_securityErrorHandler);
			return loader;
		}

		protected final function get loadingAsset():BitmapAsset
		{
			var Asset:*=getStyle("loadingImage");
			var asset:BitmapAsset=null;
			if (Asset is Class)
			{
				asset=new Asset() as BitmapAsset;
			}
			else
			{
				asset=new DefaultLoadingAsset() as BitmapAsset;
			}
			return asset;
		}

		override protected function map_changeHandler(event:MapEvent):void
		{
			super.map_changeHandler(event);

			if (!map)
			{
				return;
			}

			dispatchEvent(new ImageLayerEvent(ImageLayerEvent.LOAD));

			if (!event)
			{
				updateMaskByLoadingAsset();
			}
			else if (usePreview)
			{
				updateMaskByPreview(event.zoom, event.pan);
			}

		}

		override protected function this_closeHandler(event:MapLayerEvent):void
		{
			removeEventListener(ImageLayerEvent.LOAD, this_loadHandler);
			removeEventListener(ImageLayerEvent.LOAD_RESULT, this_loadResultHandler);
			removeEventListener(ImageLayerEvent.LOAD_FAULT, this_loadFaultHandler);

			super.this_closeHandler(event);
		}

		virtual protected function this_loadFaultHandler(event:ImageLayerEvent):void
		{
			//
		}

		virtual protected function this_loadHandler(event:ImageLayerEvent):void
		{
			//
		}

		virtual protected function this_loadResultHandler(event:ImageLayerEvent):void
		{
			//
		}

		virtual override protected function this_openHandler(event:MapLayerEvent):void
		{
			super.this_openHandler(event);

			addEventListener(ImageLayerEvent.LOAD, this_loadHandler);
			addEventListener(ImageLayerEvent.LOAD_RESULT, this_loadResultHandler);
			addEventListener(ImageLayerEvent.LOAD_FAULT, this_loadFaultHandler);
		}

		protected final function get unavailableAsset():BitmapAsset
		{
			var Asset:*=getStyle("unavailableImage");
			var asset:BitmapAsset=null;
			if (Asset is Class)
			{
				asset=new Asset() as BitmapAsset;
			}
			else
			{
				asset=new DefaultUnavailableAsset() as BitmapAsset;
			}

			return asset;
		}

		protected final function updateContainerByLoader(loader:Loader):void
		{
			if (layerContainer.contains(loader))
			{
				layerContainer.removeChild(loader);
			}
			layerContainer.addChild(loader);

			layerMask.graphics.beginFill(0xffffff, 1);
			layerMask.graphics.drawRect(loader.x, loader.y, loader.width, loader.height);
			layerMask.graphics.endFill();
		}

		protected final function updateMaskByLoaderAsset(loader:Loader, asset:BitmapAsset):void
		{
			if (layerContainer.contains(loader))
			{
				layerContainer.removeChild(loader);
			}
			layerMask.graphics.beginBitmapFill(asset.bitmapData);
			layerMask.graphics.drawRect(loader.x, loader.y, loader.width, loader.height);
			layerMask.graphics.endFill();
		}

		private final function loader_completeHandler(event:Event):void
		{
			dispatchEvent(new ImageLayerEvent(ImageLayerEvent.LOAD_RESULT));
		}

		private final function loader_ioErrorHandler(event:IOErrorEvent):void
		{
			dispatchEvent(new ImageLayerEvent(ImageLayerEvent.LOAD_FAULT, event.text));
		}

		private final function loader_securityErrorHandler(event:SecurityErrorEvent):void
		{
			dispatchEvent(new ImageLayerEvent(ImageLayerEvent.LOAD_FAULT, event.text));
		}

		private final function updateMaskByLoadingAsset():void
		{
			layerMask.graphics.clear();
			layerMask.graphics.beginBitmapFill(loadingAsset.bitmapData);
			layerMask.graphics.drawRect(-map.layers.x, -map.layers.y, width, height);
			layerMask.graphics.endFill();
		}

		private final function updateMaskByPreview(zoom:Number, pan:OGCPoint):void
		{
			updateMaskByLoadingAsset();
						
			var bitmapData:BitmapData=snapshot;
			var offsetX:Number=(1 - 1.0 / zoom) * (0.5 * width - map.layers.x);
			var offsetY:Number=(1 - 1.0 / zoom) * (0.5 * height - map.layers.y);
			var m:Matrix=new Matrix(1.0 / zoom, 0, 0, 1.0 / zoom, offsetX, offsetY);

			layerMask.graphics.beginBitmapFill(bitmapData, m, false);
			layerMask.graphics.drawRect(offsetX, offsetY, 1.0 / zoom * width, 1.0 / zoom * height);
			layerMask.graphics.endFill();
		}

	}
}
